package com.qf.smartplatform.websocket;

import com.qf.smartplatform.event.DeviceCommandEvent;
import com.qf.smartplatform.event.DeviceStatusEvent;
import com.qf.smartplatform.task.CheckStatusTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/*** @author Tgb
 * @version V1.0
 * @Project smartplatform
 * @Package com.qf.smartplatform.websocket
 * @Description:
 * @Date 2022/9/14 17:03
 */
@Component
public abstract class MyBaseWebScoketHandler extends TextWebSocketHandler {
    private ApplicationContext applicationContext;
    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    private Map<String, WebSocketSession> allCilents=new HashMap<>();
    private ConcurrentHashMap<String,Long> updateTimes=new ConcurrentHashMap<>();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String path = session.getUri().getPath();
        String deviceId = path.substring(path.lastIndexOf("/") + 1);

        session.getAttributes().put("deviceId",deviceId);
        //以设备的id作为key,将会话保存
        WebSocketSession currentSession = allCilents.get(deviceId);
        //如果设备之前有会话,就关闭
        if (currentSession!=null&&currentSession.isOpen()){
            currentSession.close();
        }
        //保存会话
        allCilents.put(deviceId,session);
        //当设备上线后,我们需要更新设备的状态为在线
        applicationContext.publishEvent(new DeviceStatusEvent(deviceId,DeviceStatusEvent.Status.ONLINE));
    }
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String deviceId = (String) session.getAttributes().get("deviceId");
        updateTimes.put(deviceId,System.currentTimeMillis());
        //因为发送过来的数据可能会有很多不同的数据,比如温湿度传感器发送的是温湿度数据,我们可以用温湿度数据作为检查存在的情况
        //其他的设备可能发送的并不是温湿度数据,是其他的内容,比如发一个ping,这样数据量比较小,减少带宽占用
        String payload = message.getPayload();
        if (!payload.isEmpty()){
            session.sendMessage(new TextMessage("pong"));
        }
        WebSocketSession webSocketSession = allCilents.get(deviceId);
        if (webSocketSession==null){
            allCilents.put(deviceId,webSocketSession);
        }
    }
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String deviceId = (String) session.getAttributes().get("deviceId");
        allCilents.remove(deviceId);
        applicationContext.publishEvent(new DeviceStatusEvent(deviceId,DeviceStatusEvent.Status.OFFLINE));

    }
    protected   int sendControl(String uuid ,String command){
        WebSocketSession webSocketSession = allCilents.get(uuid);
        if (webSocketSession!=null&&webSocketSession.isOpen()){
            try {
                webSocketSession.sendMessage(new TextMessage(command));
                return 1;
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return 0;
    }
    @EventListener
    @Async
    public void onCheckStatus(CheckStatusTask checkStatusTask){
        if (isUpdateStatus()){
            HashMap<String, Long> hashMap = new HashMap<>();
            hashMap.putAll(updateTimes);
            hashMap.forEach((deviceId,time)->{
                if (System.currentTimeMillis()-time>50000){
                    System.out.println(System.currentTimeMillis()+":::::::::::::::::::::::::::;");
                    WebSocketSession webSocketSession = allCilents.get(deviceId);
                    if (webSocketSession!=null) {
                        try {
                            webSocketSession.close();
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            });
        }
    }

    public abstract boolean isUpdateStatus();
}
